package fun.qu_an.velocity.whitelist.api.whitelist;

import fun.qu_an.lib.basic.util.result.Result;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.regex.Pattern;

/**
 * 白名单管理API，兼容在线和离线模式
 */
@SuppressWarnings({"UnusedReturnValue", "unused"})
public interface Whitelist {
	/**
	 * 判断该白名单是否是在线模式
	 *
	 * @return 该白名单是否是在线模式
	 */
	boolean isOnline();

	/**
	 * 读取白名单
	 *
	 * @return 成功则返回 {@link Result#success()}<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	Result load();

	/**
	 * 保存白名单
	 *
	 * @return 成功则返回 {@link Result#success()}<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	Result save();

	/**
	 * 添加白名单
	 *
	 * @param name 玩家名，不区分大小写
	 * @return 玩家名不合法则返回 {@link Results#ILLEGAL_PLAYER_NAME}<p>
	 * 成功则返回 {@link Result#success()} (String)}<p>
	 * 玩家已存在则返回 {@link Result#ineffective()}，消息为玩家的UUID和名称<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	Result add(String name);

	/**
	 * 添加白名单
	 * 仅在在线模式时可用
	 *
	 * @param uuid 玩家的UUID
	 * @return 离线模式时返回 {@link Results#OFFLINE}<p>
	 * 成功则返回 {@link Result#success()}<p>
	 * 玩家已存在则返回 {@link Result#ineffective()}，消息为玩家的UUID和名称<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	@Deprecated
	Result add(UUID uuid);

	/**
	 * 移除白名单
	 *
	 * @param name 玩家名，不区分大小写
	 * @return 玩家名不合法则返回 {@link Results#ILLEGAL_PLAYER_NAME}<p>
	 * 成功则返回 {@link Result#success()}，消息为玩家名<p>
	 * 玩家不存在则返回 {@link Result#ineffective()}<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	Result remove(String name);

	/**
	 * 移除白名单
	 *
	 * @param uuid 玩家UUID
	 * @return 成功则返回 {@link Result#success()}，消息为玩家名<p>
	 * 否则返回 {@link Result#ineffective()}<p>
	 */
	Result remove(UUID uuid);

	/**
	 * 获取玩家名列表
	 *
	 * @return 玩家名列表，区分大小写
	 */
	List<String> list();

	/**
	 * 根据玩家名获取UUID
	 *
	 * @param name 玩家名，不区分大小写
	 * @return 若该玩家在白名单内则返回该玩家的UUID<p>
	 * 否则返回 null
	 */
	@Nullable UUID getUuidByName(String name);

	/**
	 * 根据UUID获取玩家名
	 *
	 * @param uuid UUID
	 * @return 若该玩家在白名单内则返回该玩家的玩家名<p>
	 * 否则返回 null
	 */
	@Nullable String getNameByUuid(UUID uuid);

	/**
	 * 检查玩家是否在白名单内
	 *
	 * @param uuid 玩家的UUID
	 * @return 在白名单内返回true<p>
	 * 否则返回false
	 */
	boolean isInWhitelist(UUID uuid);

	/**
	 * 更新白名单内的玩家名
	 * 必须保证玩家名和UUID来自同一玩家
	 *
	 * @param uuid 玩家UUID
	 * @param name 玩家名
	 * @return 玩家不在白名单则返回 {@link Result#failure()}<p>
	 * 无效果则返回 {@link Result#ineffective()} ，在线模式时若API查询失败，会附带子结果({@link Result#subResult(Result)}) {@link Result#exception(Throwable)}<p>
	 * 更新成功则返回 {@link Result#success()}，消息为玩家的UUID和名称<p>
	 * 否则返回 {@link Result#exception(Throwable)}
	 */
	Result updatePlayer(UUID uuid, String name);

	/**
	 * 用于判断玩家名是否合法的判据
	 */
	Predicate<String> PLAYER_NAME_PREDICATE = Pattern.compile("[A-Za-z0-9_]+").asMatchPredicate();

	/**
	 * 检查玩家名是否合法
	 *
	 * @param name 待检查的玩家名
	 * @return 合法返回 true，否则返回 false
	 */
	@SuppressWarnings("BooleanMethodIsAlwaysInverted")
	static boolean testName(String name) {
		return PLAYER_NAME_PREDICATE.test(name);
	}

	/**
	 * 创建新的白名单
	 *
	 * @param path   json文件路径
	 * @param online 是否是在线模式
	 * @return 新的白名单实例
	 */
	@Contract("_, _ -> new")
	static @NotNull Whitelist newConcurrent(Path path, boolean online) {
		return new ConcurrentWhitelist(path, online);
	}
}
